"""
Implementation of Yolo(v2) architecture
"""
import torch
import torch.nn as nn

from .passthrough import Passthrough
from .postprocessor import PostProcessor
from .darknet import Darknet19, create_cnn_with_bn_leaky


class Yolov2(nn.Module):
    def __init__(self, in_channels=3, num_classes=20, num_anchors=5):
        super(Yolov2, self).__init__()
        self.num_classes = num_classes
        self.num_anchors = num_anchors

        # backbone
        darknet = Darknet19(in_channels=in_channels, num_classes=num_classes)
        self.conv1 = nn.Sequential(
            darknet.layer0,
            darknet.layer1,
            darknet.layer2,
            darknet.layer3,
            darknet.layer4,
        )

        self.conv2 = darknet.layer5

        # fmt: off
        self.conv3 = nn.Sequential(
            create_cnn_with_bn_leaky(1024, 1024, kernel_size=3, stride=1, padding=1, return_module=True),
            create_cnn_with_bn_leaky(1024, 1024, kernel_size=3, stride=1, padding=1, return_module=True),
        )

        self.downsampler = create_cnn_with_bn_leaky(512, 64, kernel_size=1, stride=1, padding=0, return_module=True)
        
        self.conv4 = nn.Sequential(
            create_cnn_with_bn_leaky(1024 + 64 * 4, 1024, kernel_size=3, stride=1, padding=1, return_module=True),
            nn.Conv2d(1024, (5 + self.num_classes) * self.num_anchors, kernel_size=1),
        )
        # fmt: on

        self.passthrough = Passthrough()
        self.processor = PostProcessor()

    def forward(self, x):
        x = self.conv1(x)
        shortcut = self.passthrough(self.downsampler(x))
        x = self.conv2(x)
        x = self.conv3(x)
        x = torch.cat([shortcut, x], dim=1)
        x = self.conv4(x)

        return self.processor(x)
